
//const char *g_computeShader ="																								
#if 1

#define KERNEL_SIZE_FOR_SINGLE_THREAD	4

Texture2DArray<float4>	g_tapDirLUT		: register(t0);																			
Texture2DArray<uint4>	g_extentsLUT	: register(t1);																	
Texture2DArray<uint4>	g_sourceTexture	: register(t2);																		
																															
RWTexture2D<float4>	g_result	: register(u0);																				
																															
cbuffer asd : register(b0)																									
{																															
	float	dotProdThresh;																									
	float	specularPower;																									
	float	isPhongBRDF;																									
	float	faceIndex;																										
	float	tapdirMip;																										
	float	filterExtentMip;																								
	float	dstImageSize;																									
	float	mainTapdirMip;																									
	int		offsetX;																										
	int		offsetY;																										
	int		threadPerFilterExtent;
	int		padding2;																										
};																															

groupshared float4 reductionArea[16][16];

[numthreads(16,16,1)]																											
void main(uint3 gt : SV_DispatchThreadID, uint3 gid : SV_GroupID, uint3 gtid : SV_GroupThreadID )																					
{		
	const uint2 g_threadPerFilterExtent = uint2(threadPerFilterExtent, threadPerFilterExtent);
	uint2 targetPixelIndex = gt / g_threadPerFilterExtent;
	uint2 feIndex = gt.xy - targetPixelIndex * g_threadPerFilterExtent;
	{																														
		float4 mainTapDir = g_tapDirLUT.Load(int4(targetPixelIndex.xy, int(faceIndex), int(mainTapdirMip)));
		
		float4 dstAccum = 0;																								
		float weightAccum = 0;																								
		float spec_pow = specularPower + isPhongBRDF;																		
																															
		for (uint i_face = 0; i_face < 6; i_face++)																			
		{																													
			int2 extentsUV = targetPixelIndex.xy * int2(6, 1) + int2(i_face, 0);

			uint4 faceExtents = g_extentsLUT.Load(int4(extentsUV, int(faceIndex), int(filterExtentMip)));
			faceExtents.xy += feIndex;

			//if (faceExtents.x < faceExtents.z)																			
			{																												
				//if (faceExtents.y < faceExtents.w)																		
				{				
					for (uint i_x = faceExtents.x; i_x < faceExtents.z; i_x += threadPerFilterExtent)
					{																										
						for (uint i_y = faceExtents.y; i_y < faceExtents.w; i_y += threadPerFilterExtent)
						{																									
							float4 tapDir = g_tapDirLUT.Load(int4(i_x, i_y, i_face, tapdirMip));
																															
							float tapDotProd = dot(tapDir.xyz, mainTapDir.xyz);												
																															
							if(tapDotProd >= dotProdThresh && tapDotProd > 0.0)												
							{																								
								float weight = tapDir.w;																	
								weight *= pow(tapDotProd, spec_pow);														
																															
								float4 srcTexture = g_sourceTexture.Load(int4(i_x, i_y, i_face, 0)) / 255.0;
																															
								dstAccum += weight * srcTexture;															
																															
								weightAccum += weight;																		
							}																								
						}																									
					}																										
																															
				}																											
			}																												
		}																													
																															
		if (weightAccum != 0)																								
		{
			dstAccum /= weightAccum;
		}
// 		else																												
// 		{																													
// 			dstAccum = g_sourceTexture.Load(int4(gt.xy, int(faceIndex), 0));												
// 		}																													
		
		if (threadPerFilterExtent == 1)
		{
			//g_result[int2(targetPixelIndex)] = float4(dstAccum.rgb, 1);
			if (all(feIndex == 0))
			{
				g_result[int2(targetPixelIndex)] = float4(dstAccum.rgb, 1);
			}
		}
		else
		{
			reductionArea[gtid.x][gtid.y] = dstAccum;

			GroupMemoryBarrierWithGroupSync();

			uint2 reductionStart = (gtid / g_threadPerFilterExtent) * g_threadPerFilterExtent;

			if (all(feIndex == 0))
			{
				float4 res = 0;
				for (int i_x = 0; i_x < 8; i_x++)
				{
					for (int i_y = 0; i_y < 8; i_y++)
					{
						res += reductionArea[reductionStart.x + i_x][reductionStart.y + i_y];
					}
				}
				g_result[int2(targetPixelIndex)] = float4(res.rgb / 64.0, 1);
				//g_result[int2(targetPixelIndex)] = float4(mainTapDir.rgb, 1);
				//g_result[int2(targetPixelIndex)] = float4(targetPixelIndex.xy / 128.0, 1, 1);
			}
		}
		
// 		else
// 		{
// 			g_result[int2(targetPixelIndex)] = float4(0,0,1, 1);
// 		}
		//g_result[int2(gt.xy)] = float4(g_sourceTexture.Load(int4(gt.xy, int(faceIndex), 0)).xyz,1);						
	}																														
}


/*
Changes

source converted to uint from unorm

*/

#else

#define SOURCE_IMAGE_SIZE 256
#define TGSM_CACHE_GRID_SIZE 32
#define THREAD_COUNT 16
#define TGSM_PIXEL_LOAD_PER_THREAD (TGSM_CACHE_GRID_SIZE / THREAD_COUNT)

Texture2DArray<float4>	g_tapDirLUT		: register(t0);																			
Texture2DArray<uint4>	g_extentsLUT	: register(t1);																	
Texture2DArray<uint4>	g_sourceTexture	: register(t2);																		
																															
RWTexture2D<float4>	g_result	: register(u0);																				
																															
cbuffer asd : register(b0)																									
{																															
	float	dotProdThresh;		
	float	specularPower;		
	float	isPhongBRDF;		
	float	faceIndex;			
	float	tapdirMip;			
	float	filterExtentMip;	
	float	dstImageSize;		
	float	mainTapdirMip;		
	int		offsetX;			
	int		offsetY;			
	int		padding1;			
	int		padding2;			
};																															

groupshared uint faceCache[TGSM_CACHE_GRID_SIZE][TGSM_CACHE_GRID_SIZE];
static const int2 g_cacgeGridSize = int2(TGSM_CACHE_GRID_SIZE, TGSM_CACHE_GRID_SIZE);

[numthreads(THREAD_COUNT, THREAD_COUNT, 1)]
void main(uint3 dt : SV_DispatchThreadID, uint3 gt : SV_GroupThreadID)
{	
		//Transfer data to shared memory
		int cacheGridDim = SOURCE_IMAGE_SIZE / TGSM_CACHE_GRID_SIZE;

		float4 dstAccum = 0;
		float weightAccum = 0;


		//for (uint i_face = 0; i_face < 6; i_face++)
		int i_face = 0;
		{
			for (int i_row = 0; i_row < cacheGridDim; i_row++)
			{
				for (int i_col = 0; i_col < cacheGridDim; i_col++)
				{
					int2 cacheGridStart = int2(i_col, i_row) * g_cacgeGridSize;
					int2 cacheGridEnd = cacheGridStart + g_cacgeGridSize;

					for (int x = gt.x * TGSM_PIXEL_LOAD_PER_THREAD; x < (gt.x + 1) * TGSM_PIXEL_LOAD_PER_THREAD ; x++)
					{
						for (int y = gt.y * TGSM_PIXEL_LOAD_PER_THREAD; y < (gt.y + 1) * TGSM_PIXEL_LOAD_PER_THREAD ; y++)
						{
							faceCache[x][y] = g_sourceTexture.Load(int4(cacheGridStart.x + x, cacheGridStart.y + y, i_face, 0));
							//faceCache[x][y] = x*8;
						}
					}

					GroupMemoryBarrierWithGroupSync();

					float4 mainTapDir = g_tapDirLUT.Load(int4(dt.xy, int(faceIndex), int(mainTapdirMip)));
					float spec_pow = specularPower + isPhongBRDF;

					int2 extentsUV = dt.xy * int2(6, 1) + int2(i_face, 0);
					uint4 faceExtents = g_extentsLUT.Load(int4(extentsUV, int(faceIndex), int(filterExtentMip)));

					//if (faceExtents.x < faceExtents.z)
					{
						//if (faceExtents.y < faceExtents.w)
						{
							uint2 faceExtentsStart = max(cacheGridStart, faceExtents.xy);
							uint2 faceExtentsEnd = min(cacheGridEnd, faceExtents.zw);

							for (uint i_x = faceExtentsStart.x; i_x < faceExtentsEnd.x; i_x++)
							{
								for (uint i_y = faceExtentsStart.y; i_y < faceExtentsEnd.y; i_y++)
								{
									float4 tapDir = g_tapDirLUT.Load(int4(i_x, i_y, i_face, tapdirMip));
										float tapDotProd = dot(tapDir.xyz, mainTapDir.xyz);
									if (tapDotProd >= dotProdThresh && tapDotProd > 0.0)
									{
										float weight = tapDir.w;
										weight *= pow(tapDotProd, spec_pow);

										//float4 srcTexture = g_sourceTexture.Load(int4(i_x, i_y, i_face, 0)) / 255.0;
										float4 srcTexture = faceCache[i_x - cacheGridStart.x][i_y - cacheGridStart.y] / 255.0;

											dstAccum += weight * srcTexture;

										weightAccum += weight;
									}
								}
							}
						}
					}								
				}
			}
		}

		if (weightAccum != 0)
		{
			dstAccum /= weightAccum;
		}
		else
		{
			dstAccum = g_sourceTexture.Load(int4(dt.xy, int(faceIndex), 0));
		}

		g_result[int2(dt.xy)] = float4(dstAccum.rgb, 1);
		//g_result[int2(gt.xy)] = g_sourceTexture.Load(int4(gt.x, gt.y, faceIndex, 0)) /255.0;
}

#endif